#pragma once

#include "Logger.hpp"
#include "Epoller.hpp"
#include "TimerWheel.hpp"
#include "Channel.hpp"

#include <thread>
#include <sys/eventfd.h>

#include "Socket.hpp"

using namespace SocketModule;

using namespace std;
using namespace LogMudule;


//是对Epoller模块，TimerWheel模块，Socket模块的⼀个整体封装（组合）
//对所有事件监控（包括socketfd的IO事件，TimerQueue模块定时任务）
class Reactor
{
    // 任务对列中的任务的类型
    typedef function<void()> task_t;

private:
    // 当前这个Reactor对应的线程的ID
    thread::id _this_thread_id;
    // 用于唤醒阻塞在epoll_wait中等待fd就绪的Ractor线程
    int _event_fd;
    //_event_fd对应的Channle对象，用来把_event_fd放进Epoller中进行监控
    Channel _eventfd_channel;

    // 负责fd事件监控（以及自动调用回调）
    Epoller _epoll;
    // 定时器（管理定时任务）
    TimerWheel _timer_wheel;

    // 任务队列
    vector<task_t> _task_queue;
    // 保护任务队列的锁
    mutex _mutex;

private:
    // 创建eventfd
    static int CreateEventFd()
    {
        // 创建并且初始值为0，禁止进程拷贝
        int fd = eventfd(0, EFD_CLOEXEC);
        if (fd < 0)
        {
            LOG(LogLevel::DEADLY) << "eventfd创建失败!!!";
            abort();
        }
        return fd;
    }
    // 让Reactor对应的线程执行任务队列中的所有任务
    void RunAllTask()
    {
        // 用于暂时保存任务
        vector<task_t> tmp_tasks;
        {
            // 加锁保护任务队列
            lock_guard<mutex> m(_mutex);
            // 把任务队列中的所有任务都取出来
            tmp_tasks.swap(_task_queue);
        }
        // 解锁之后再执行任务
        for (auto &task : tmp_tasks)
        {
            task();
        }
    }
    // eventfd读事件就绪时，要调用的读回调
    void ReadEventFd()
    {
        // 注意：一次只能读取8字节
        uint64_t val = 0;
        int ret = read(_event_fd, &val, sizeof(val));
        if (ret < 0)
        {
            // 如果被信号中断
            if (errno == EINTR)
            {
                LOG(LogLevel::DEBUG) << "Reactor:阻塞读取eventfd被信号中断";
                return;
            }
            LOG(LogLevel::DEADLY) << "读取eventfd失败，eventfd损坏!!!";
            abort();
        }
    }
    // 向eventfd写入数据，唤醒可能阻塞再epoll_wait里面的Reactor线程
    void WeakUpEventFd()
    {
        // 注意：一次只能写入8字节
        uint64_t val = 1;
        int ret = write(_event_fd, &val, sizeof(val));
        if (ret < 0)
        {
            // 如果被信号中断
            if (errno == EINTR)
            {
                LOG(LogLevel::DEBUG) << "Reactor:阻塞写入eventfd被信号中断";
                return;
            }
            LOG(LogLevel::DEADLY) << "写入eventfd失败，eventfd损坏!!!";
            abort();
        }
    }
    // 判断执行该函数的线程，是不是当前Reactor对应的那个线程
    bool IsThisThread()
    {
        if (this_thread::get_id() == _this_thread_id)
            return true;
        else
            return false;
    }
public:
    Reactor()
        : _this_thread_id(this_thread::get_id()),
          _event_fd(CreateEventFd()),
          _eventfd_channel(this, _event_fd),
          _timer_wheel(this)
    {
        //把_event_fd设置为非阻塞
        SocketModule::FdSetNonBlock(_event_fd);

        // 把void ReadEventfd()作为读回调注册给_eventfd_channel
        _eventfd_channel.SetReadCallback(std::bind(&Reactor::ReadEventFd, this));
        // 启动_eventfd_channel的读事件关心
        _eventfd_channel.EnableRead();
    }
    // 将连接操作添加到任务队列
    void QueueInLoop(const task_t &t)
    {
        {
            // 加锁保护任务队列
            lock_guard<mutex> m(_mutex);
            _task_queue.emplace_back(t);
        }
        // 向eventfd写入数据，唤醒可能阻塞在epoll_wait里面的Reactor线程
        WeakUpEventFd();
    }

    // 组件外部的使用者能够执行的对连接的所有操作的接口，都会被组件通过RunInLoop进行一次封装
    void RunInLoop(const task_t &task)
    {
        // 如果执行该函数的是该reactor对象自己对应的那个线程
        if (IsThisThread())
        {
            // 就直接执行任务
            task();
        }
        else // 否则
        {
            // 就放进任务队列中
            QueueInLoop(task);
        }
    }
    // 添加定时任务
    void AddTimerTask(uint64_t id, uint32_t timeout, const task_t &task)
    {
        _timer_wheel.AddTimerTask(id, timeout, task);
    }
    // 刷新定时任务，延迟超时时间
    void RefreshTimerTask(uint64_t id,uint32_t time)
    {
        _timer_wheel.RefreshTimerTask(id,time);
    }
    // 取消指定定时任务
    void CanceledTimerTask(uint64_t id)
    {
        _timer_wheel.CanceledTimerTask(id);
    }
    // 判断一个定时任务是否存在
    // 注意：这个接口虽然是公有的，而且是对定时任务的操作
    // 但是只是给组件内使用，并不提供提供给组件外使用
    bool HasTimerTask(uint64_t id)
    {
        return _timer_wheel.HasTimerTask(id);
    }
    
    //判断是否已经监控了某个Channel对象
    bool HasChannel(Channel*chnnel)
    {
        return _epoll.HasChannel(chnnel);
    }

    // 新增/修改指定Channel关心的事件，Channel已经监控了就修改，没有监控就添加
    void UpdateEvent(Channel *channel)
    {
        _epoll.UpdateEvent(channel);
    }
    // 删除指定的Channel关心的事件，并在哈希表（_channels）中将其删除
    void RemoveEvent(Channel *channel)
    {
        _epoll.RemoveEvent(channel);
    }

    // 启动事件监控
    void Start()
    {
        while (true)
        {
            // 开始事件监控
            vector<Channel *> rchannels;
            _epoll.Poll(&rchannels);

            // 遍历所有就绪事件（Channel）
            for (auto &rcha : rchannels)
            {
                // 根据触发的事件调用对应回调处理就绪事件
                rcha->HandleEvents();
            }

            // 执行任务队列中的函数
            RunAllTask();
        }
    }
    ~Reactor()
    {
        //移除_event_fd的事件监控
        _eventfd_channel.Remove();
        ::close(_event_fd);
    }
};

// 把Channel自己对事件的更新同步到Reactor模块中的Epoller
void Channel::Update()
{
    _belongs_reactor->UpdateEvent(this);
}

// 把当前fd从epoll模型中移除
void Channel::Remove()
{
    // 对事件的更新同步到Reactor模块中的Epoller
    _belongs_reactor->RemoveEvent(this);
}


//判断当前fd是否在epoll模型中被监控
bool Channel::IsSurveillance()
{
    // 对事件的更新同步到Reactor模块中的Epoller
    return _belongs_reactor->HasChannel(this);
}

// 添加定时任务
void TimerWheel::AddTimerTask(uint64_t id, uint32_t timeout, const function<void()> &task)
{
    _belongs_reactor->RunInLoop(std::bind(&TimerWheel::AddTimerTaskInLoop, this, id, timeout, task));
}
// 刷新定时任务，延迟超时时间
void TimerWheel::RefreshTimerTask(uint64_t id,uint32_t time)
{
    _belongs_reactor->RunInLoop(std::bind(&TimerWheel::RefreshTimerTaskInLoop, this, id,time));
}
// 取消指定定时任务
void TimerWheel::CanceledTimerTask(uint64_t id)
{
    _belongs_reactor->RunInLoop(std::bind(&TimerWheel::CanceledTimerTaskInLoop, this, id));
}
